/* tripl/arch/cstyles.c 
 * 
 * This file is part of tripl. 
 * 
 * tripl is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version. 
 * 
 * tripl is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with tripl. If not, see <https://www.gnu.org/licenses/>
 */ 




#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>

#include <errno.h>

#include <klist.h>
#include <tripl/tripl.h>
#include <tripl/limits.h>
#include <tripl/arch.h>



/* compatible of c-style function defines */


/* arch/arch_templ.c */
int find_name(char *name);

extern struct klist_node names_list;
extern char *psave;


const static char *c_keywords[] = {
	"char", 	"double", 	"enum", 	"float", 
	"int", 		"long", 	"short", 	"signed", 
	"struct", 	"union", 	"unsigned", 	"void", 

	"for", 		"do", 		"while", 	"break", 
	"continue", 

	"if", 		"else", 	"goto", 

	"switch", 	"case", 	"default", 

	"return", 

	"auto", 	"extern", 	"register", 	"static", 

	"const", 	"sizeof", 	"typedef", 	"volatile", 

	"inline", 	"restrict", 	"_Bool", 	"_Complex", 
	"_Imaginary"
};


static int iskeyword(char *p, int l) {
	int i;

	for (i = 0; i < arrlen(c_keywords); i++) 
		if (!strncmp(c_keywords[i], p, l)) 
			return 1;

	return 0;
}


__arch_templ int cstyle_declare(char *p, struct arch *arch_fn) {
	/* return-type function-name ( argument-type-1 argument-name, ...) 
	 *
	 * and the preprocess is MUST done, so only keywords are before functions.
	 * and an important thing is, we will do some check with the c-style declares. */

	struct klist_node *n;
	int type, out, nargs = 0, have_args = 0;
	char *fname;


	/* get function name */

	_skip_spaces(p);

	for (;;) {
		getword(p, &type, &out);

		if (type == WORDTYPE_NAME) {
			if (iskeyword(p, out)) {
				p += out;
				_skip_spaces(p);

				continue;
			}
		}

		else if (type == WORDTYPE_KWORD) 
			if (out == '*') {
				p++;
				_skip_spaces(p);

				continue;
			}

		/* now we found the name */

		break;
	}

	fname = strndup(p, out);

	p += out;
	_skip_spaces(p);

	getword(p, &type, &out);

	if (unlikely(type != WORDTYPE_KWORD || out != '(')) 
		/* not a c-style declare */
		return 0;

	p++;
	_skip_spaces(p);

	while (getword(p, &type, &out)) {
		switch (type) {
		case WORDTYPE_NAME:
/*			no, no this. think about : 
 *
 *			int add(int, int);
 *
 *			if (!iskeyword(p, out)) 
 *				nargs++; */
			
			p += out;
			_skip_spaces(p);

			break;

		case WORDTYPE_KWORD:
			if (*p == ',') {
				have_args = 1;

				nargs++;
			}

			p++;
			_skip_spaces(p);

			break;

		case WORDTYPE_NR:
		default:
			exit(generic_error("invalid c-style declare: are you kidding me? ", psave, lno));
		}
	}

	if (have_args) 
		/* ',' means two arguments */
		nargs++;

	/* join to the function-list */

	n = malloc(sizeof(struct klist_node));
	klist_init(n);


	if (!nargs) 
		n->value = DECLARE_FN | DECLARE_NOARG;

	else 
		n->value = DECLARE_FN | nargs;

	n->xmask = XMASK_WEAK | XMASK_FN;

	n->payload = fname;

	if (find_name(n->payload)) {
		error((char *) n->payload);

		exit(generic_error("name already defined", psave, lno));
	}

	klist_add(&names_list, n);

	return 1;
}


